package com.koron.order.linepatrol.satellite.excel;

import com.alibaba.excel.event.AnalysisEventListener;
import com.koron.bean.system.org.OrgBean;
import com.koron.bean.system.staff.StaffBean;
import com.koron.common.core.business.common.mapper.StaffMapper;
import com.koron.common.core.business.configsettings.utils.ConfigInfoTool;
import com.koron.common.core.config.ThreadLocalContext;
import com.koron.order.overhaul.bean.dto.Equipment;
import com.koron.order.risk.base.excel.ExcelError;
import com.koron.order.risk.base.mapper.LineEquipmentMapper;
import lombok.extern.slf4j.Slf4j;
import org.koron.ebs.mybatis.SessionFactory;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 * @author jzp
 * @since 2023/2/8
 */
@Slf4j
public abstract class LineAnalysisEventListener<T> extends AnalysisEventListener<T> {

    // 人员缓存
    private final Map<String, String> staffCache = new HashMap<>();
    // 部门缓存
    private final Map<String, String> deptCache = new HashMap<>();
    // 设备缓存
    private final Equipment rootEquipment = allLineEquipment();

    // 错误数据信息
    private final List<T> errorRisk = new ArrayList<>();
    // 错误备注信息
    private final Map<Integer, ExcelError> excelErrors = new HashMap<>();

    public String getCurrDs() {
        return ThreadLocalContext.get().getCurrDs();
    }

    public void fillError(T data, int collIndex, String tip) {
        errorRisk.add(data);
        ExcelError excelError = new ExcelError(errorRisk.size(), collIndex, tip);
        excelErrors.put(errorRisk.size()+1, excelError);
        log.error(tip);
    }

    // 根据姓名获取账号
    public String getStaffAccountByName(String name) {
        if (staffCache.containsKey(name)) {
            return staffCache.get(name);
        }
        StaffBean staffBean = new StaffBean();
        staffBean.setName(name);
        staffBean.setAppId(ThreadLocalContext.get().getAppId());
        String[] split = name.split("\\|", 2);
        if (split.length == 2) {
            staffBean.setName(split[0]);
            staffBean.setAccount(split[1]);
        }
        try (SessionFactory factory = new SessionFactory()) {
            StaffMapper mapper = factory.getMapper(StaffMapper.class);
            List<StaffBean> staffBeans = mapper.selectList(staffBean);
            // 用户不存在
            if (staffBeans == null || staffBeans.size() == 0) {
                staffCache.put(name, null);
                return null;
            } else if (staffBeans.size() > 1) {
                // 同名用户
                staffCache.put(name, "");
                return "";
            }
            staffCache.put(name, staffBeans.get(0).getAccount());
            return staffBeans.get(0).getAccount();
        }
    }

    // 根据部门名称获取id
    public String getDeptIdByName(String name) {
        if (deptCache.containsKey(name)) {
            return deptCache.get(name);
        }
        OrgBean orgBean = new OrgBean();
        orgBean.setName(name);
        orgBean.setAppid(ThreadLocalContext.get().getAppId());
        String[] split = name.split("\\|", 2);
        if (split.length == 2) {
            orgBean.setName(split[0]);
            orgBean.setId(split[1]);
        }
        try (SessionFactory factory = new SessionFactory()) {
            StaffMapper mapper = factory.getMapper(StaffMapper.class);
            List<OrgBean> orgBeans = mapper.selectOrgList(orgBean);
            // 用户不存在
            if (orgBeans == null || orgBeans.size() == 0) {
                deptCache.put(name, null);
                return null;
            } else if (orgBeans.size() > 1) {
                // 同名用户
                deptCache.put(name, "");
                return "";
            }
            deptCache.put(name, orgBeans.get(0).getId());
            return orgBeans.get(0).getId();
        }
    }

    // 根据线路名称获取id
    public Equipment getLineByName(String name) {
        List<Equipment> children = rootEquipment.getChildren();
        List<Equipment> lines = children.stream().filter(e -> name.equals(e.getName())).collect(Collectors.toList());
        if (lines.isEmpty()) {
            return null;
        } else {
            return lines.get(0);
        }
    }

    // 根据钢塔名称从给出的钢塔数据中查到对应的杆塔
    public Equipment getTowerByNameAndChildren(String parentName, String name, List<Equipment> children) {
        // 兼容前缀
        name = name.startsWith(parentName) ? name : parentName + name;
        // 兼容后缀
        String finalName = name.endsWith("塔") ? name : name + '塔';

        List<Equipment> lines = children.stream().filter(e -> finalName.equals(e.getName())).collect(Collectors.toList());
        if (lines.isEmpty()) {
            return null;
        } else {
            return lines.get(0);
        }
    }

    // 根据钢塔名称从给出的钢塔数据中查到对应的杆塔集合
    public List<Equipment> getTowersByNamesAndChildren(String parentName, String names, List<Equipment> children) {
        // 拿到第一个和最后一个
        String[] split = names.split("[~-、,，\n]");
        if (split.length > 2) {
            // 只需要有两个杆塔，即第一个和最后一个
            return new ArrayList<>();
        }
        // 兼容前缀
        String firstTowerName = split[0].startsWith(parentName) ? split[0] : parentName + split[0];
        String lastTowerName = split.length == 2 ? (split[1].startsWith(parentName) ? split[1] : parentName + split[1]) : null;

        int[] firstTowerIndexs = IntStream.range(0, children.size()).filter(i -> firstTowerName.equals(children.get(i).getName())).toArray();
        int firstTowerIndex;
        if (firstTowerIndexs.length == 0) {
            return null;
        } else {
            firstTowerIndex = firstTowerIndexs[0];
        }

        int lastTowerIndex = -1;
        if (lastTowerName != null) {
            int[] lastTowerIndexs = IntStream.range(0, children.size()).filter(i -> lastTowerName.equals(children.get(i).getName())).toArray();
            if (lastTowerIndexs.length == 0) {
                return null;
            } else {
                lastTowerIndex = lastTowerIndexs[0];
            }
        }

        if (lastTowerIndex == -1) {
            return Collections.singletonList(children.get(firstTowerIndex));
        }
        return children.subList(firstTowerIndex, lastTowerIndex+1);
    }

    // 所有的线路设备数据
    public Equipment allLineEquipment() {
        // 1. 查询根设备
        Map<String, String> config = ConfigInfoTool.getConfigByCode("equipment", "line_root_device");
        String id = config.get("id");
        try (SessionFactory factory = new SessionFactory()) {
            factory.setDbEnv(getCurrDs());
            LineEquipmentMapper mapper = factory.getMapper(LineEquipmentMapper.class);
            Equipment root = mapper.getById(id);
            List<Equipment> equipmentList = mapper.selectSimpleLineEquipment(root.getLevelPath(), root.getLevel() + 3);
            // 线路设备
            Map<String, Equipment> lineEquipmentMap = new HashMap<>();
            for (Equipment equipment : equipmentList) {
                // 本身equipmentList就是有序的
                // 添加线路设备
                String parentId = equipment.getParentId();
                if (parentId.equals(root.getId())) {
                    if (root.getChildren() == null) {
                        root.setChildren(new ArrayList<>(Collections.singletonList(equipment)));
                    } else {
                        List<Equipment> children = root.getChildren();
                        children.add(equipment);
                    }
                    lineEquipmentMap.put(equipment.getId(), equipment);
                }

                // 添加杆塔
                if (lineEquipmentMap.containsKey(parentId)) {
                    Equipment parent = lineEquipmentMap.get(parentId);
                    if (parent.getChildren() == null) {
                        parent.setChildren(new ArrayList<>(Collections.singletonList(equipment)));
                    } else {
                        List<Equipment> children = parent.getChildren();
                        children.add(equipment);
                    }
                }
            }
            return root;
        }
    }

    public List<T> getErrorRisk() {
        return errorRisk;
    }

    public List<ExcelError> getExcelErrors() {
        return new ArrayList<>(excelErrors.values());
    }
}
